<?php
namespace Trade\Model;
use Common\Model\VirtualModel;
use Think\Log;

class WeChatPayModel extends VirtualModel{
    private $appID="wx7d972a70edd7b03c";//应用ID
    private $mchID="1497728632";//商户号
    private $key="AaBbCcDdEeFfa2172455AaBbCcDdEeFf";//密钥
    private $notifyUrl="http://115.159.192.243/qy/Trade/Notify/weChat";//回调地址
    
    //生成签名
    public function generateSignature($data,$type){
        ksort($data);
        $data["key"]=$this->key;
        $queryArr=[];
        foreach($data as $key => $value){
            $queryArr[]=$key ."=". $value ;
        }
        $queryStr=join("&",$queryArr);
        $sign=strtoupper(md5($queryStr));
        //注：HMAC-SHA256签名方式
        //$sign=strtoupper(hash_hmac("sha256",$queryStr,$this->key));
        return $sign;
    }
    //将要发送给微信服务器的内容进行编码
    public function stringifyContent($content){
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $xml=$dom->createElement("xml");
        $dom->appendChild($xml);
        foreach($content as $key => $value){
            $node=$dom->createElement($key,$value);
            $xml->appendChild($node);
        }
        return $dom->saveXML();
    } 
    //解析微信服务器返回的数据
    public function parseContent($str){
        // $obj=simplexml_load_string($str);
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->loadXML($str);
        $xml=$dom->getElementsByTagName("xml")->item(0);
        $response=[];
        foreach($xml->childNodes as $node){
            $response[$node->localName] = $node->textContent;
        }
        if(!$response){
            $this->error="无法解析微信服务器返回的数据";
            return false;
        }
        if($response["return_code"]!=="SUCCESS"){
            $this->error=$response["return_msg"];
            return false;
        }
        return $response;
    }
    //向微信的服务器发送请求，按照微信服务器需要的格式统一编码和签名
    public function postWxRequest($url,$content){
        $content["sign"]=$this->generateSignature($content,"request");
        $curl = new \Curl();
        $str=$this->stringifyContent($content);
        $result = $curl->post($url, $str);
        if(!$result){
            $this->error="创建订单失败";
            return false;
        }
        $response=$this->parseContent($result);
        if(!$response){
            return false;
        }
        return $response;
    }
    //调用统一下单接口生成支付订单(只支持APP调用)
    public function createOrder($data){
        $content=[
            "appid"=>$this->appID,
            "attach"=>$data["title"],
            "body"=>$data["description"],
            "mch_id"=>$this->mchID,
            "nonce_str"=>sp_random_string(32),
            "notify_url"=>$this->notifyUrl,
            "out_trade_no"=>$data["trade_no"],
            "spbill_create_ip"=>get_client_ip(),
            "total_fee"=>$data["money"]*100,
            "trade_type"=>"APP"
        ];
        $url="https://api.mch.weixin.qq.com/pay/unifiedorder";
        $response=$this->postWxRequest($url,$content);
        if(!$response){
            return false;
        }
        $content=[
            "appid"=>$this->appID,
            "partnerid"=>$this->mchID,
            "prepayid"=>$response["prepay_id"],
            "noncestr"=>sp_random_string(32),
            "timestamp"=>time(),
            "package"=>"Sign=WXPay"
        ];
        $content["sign"]=$this->generateSignature($content,"pay");
        return $content;
    }
    //查询订单
    public function query($tradeNo=null,$outTradeNo=null){
        $content=[
            "appid"=>$this->appID,
            "mch_id"=>$this->mchID,
            "nonce_str"=>sp_random_string(32)
        ];
        if($outTradeNo){
            $content["transaction_id"]=$outTradeNo;
        }
        elseif($tradeNo){
            $content["out_trade_no"]=$tradeNo;
        }
        else{
            $this->error="需要输入交易编号或微信交易编号";
            return false;
        }
        $url="https://api.mch.weixin.qq.com/pay/orderquery";
        return $this->postWxRequest($url,$content);
    }
    //前端查询是否支付成功
    public function verifyReturn($data){
        $params=$this->query($data["trade_no"],$data["out_trade_no"]);
        return $params["result_code"]==="SUCCESS";
    }
    //接收回调消息
    public function verifyNotify(){
        $text=file_get_contents('php://input');
        $response=$this->parseContent($text);
        if(!$response){
            return false;
        }
        //验证签名
        $sign=$response["sign"];
        unset($response["sign"]);
        $realSign=$this->generateSignature($response,"notify");
        Log::record("[WeChat] type:notify appID:".$this->appID." transaction_id:".$response["transaction_id"]."  sign:$realSign",Log::DEBUG);
        if($realSign!==$sign){
            $this->error="签名验证失败";
            Log::record("[WeChat] error:".$this->error." ".$text,Log::DEBUG);
            $params=$this->query($response["out_trade_no"],$response["transaction_id"]);
            Log::record("[WeChat] 主动查询结果:".$params["result_code"],Log::DEBUG);
            if($params["result_code"]!=="SUCCESS"){
                return false;
            }
        }
        return $response;
    }
    //回复回调消息
    public function replyNotify($result,$message=""){
        $data=[
            "return_code"=>$result ? "SUCCESS" : "FAIL",
            "return_msg"=>$result ? "OK" : $message
        ];
        echo $this->stringifyContent($data);
        exit;
    }
}